<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>共享画布</title>
  <link type="text/css" rel="styleSheet" href="./index.css" />
  <script src="./react.js"></script>
  <script src="./react-dom.js"></script>
  <script src="./babel.js"></script>
</head>

<body>
  <div id="root"></div>
  <script type="text/babel">
    const baseURL = '47.93.221.26:8080'
    let ws, ctx;
    const Method = {
      PEN: 'pen',
      TRIANGLE: 'triangle',
      RECTANGLE: 'rectangle',
      CIRCLE: 'circle',
      TEXT: 'text'
    }
    //工具组件
    function Tools(props) {
      const { setPaints, paints, setActivePaint } = props;
      const { useRef, useState, useEffect } = React;
      let time = useRef(null)
      useEffect(() => {
        let num = 0;
        setInterval(() => {
          let hour = Math.floor(num / 3600);
          let min = Math.floor((num % 3600) / 60);
          let sec = num % 60;
          hour = hour < 10 ? '0' + hour : hour;
          min = min < 10 ? '0' + min : min;
          sec = sec < 10 ? '0' + sec : sec;
          time.current.innerText = hour + ':' + min + ":" + sec;
          num++;
        }, 1000)
      }, [])

      function close() {
        let a = document.createElement('a');
        a.href = "http://" + baseURL + "/front/test.html";
        a.target = "_self";
        a.click();
      }
      function addPaint() {
        setPaints(paints => [...paints, null])
        setActivePaint(() => paints.length)
      }
      return (
        <div id="tools">
          <div id="time" ref={time}>00:00:00</div>
          <div onClick={addPaint} id="addPaint" title="新建画布"></div>
          <button id="close" onClick={close}>结束会议</button>
        </div>
      )
    }

    function Pen(props) {
      const { setColor, setSize } = props.setPaintStyle;
      const { setMethod, method, setIsPadding, setText } = props;
      const { useState, useRef, useEffect } = React;
      let inputColor = useRef(null);
      let inputSize = useRef(null);
      let inputText = useRef(null);

      useEffect(() => {
        inputColor.current.disabled = true;
      })
      function selectColor() {
        inputColor.current.disabled = false;
        inputColor.current.click();
      }

      function selectSize(e) {
        if (inputSize.current.className) {
          inputSize.current.disabled = false;
          inputSize.current.className = ''
        } else {
          inputSize.current.disabled = true;
          inputSize.current.className = 'noShow'
        }
      }

      function selectText() {
        if (inputText.current.className) {
          inputText.current.className = ''
        } else {
          inputText.current.className = 'noShow'
        }
      }
      return (
        <div id="Pen">
          <div id="penSelector" className="paintStyle" onClick={() => { setMethod(() => Method.PEN) }}></div>
          <div id="colorSelector" className="paintStyle" onClick={selectColor} title="color"></div><input type="color" className="noShow" onChange={(e) => { setColor(e.target.value); inputColor.current.disabled = true; }} ref={inputColor} />
          <div id="sizeSelector" className="paintStyle" onClick={selectSize} title="size"></div><input type="range" className="noShow" min="1" max="20" step="1" defaultValue="1" onChange={(e) => { setSize(e.target.value) }} ref={inputSize} />
          <div id="triangleSelector" className="paintStyle" onClick={() => { setMethod(() => Method.TRIANGLE); setIsPadding(() => false) }}></div>
          <div id="rectangleSelector" className="paintStyle" onClick={() => { setMethod(() => Method.RECTANGLE); setIsPadding(() => false) }}></div>
          <div id="circleSelector" className="paintStyle" onClick={() => { setMethod(() => Method.CIRCLE); setIsPadding(() => false) }}></div>
          <div id="textSelector" className="paintStyle" onClick={() => { setMethod(() => Method.TEXT); setIsPadding(() => false); selectText() }}></div>
          <div id="fillTriangleSelector" className="paintStyle" onClick={() => { setMethod(() => Method.TRIANGLE); setIsPadding(() => true) }}></div>
          <div id="fillCircleSelector" className="paintStyle" onClick={() => { setMethod(() => Method.CIRCLE); setIsPadding(() => true) }}></div>
          <div id="fillRectangleSelector" className="paintStyle" onClick={() => { setMethod(() => Method.RECTANGLE); setIsPadding(() => true) }}></div>
          <div id="fillTextSelector" className="paintStyle" onClick={() => { setMethod(() => Method.TEXT); setIsPadding(() => true); selectText() }}></div>
          <input type="text" ref={inputText} id="text" className="noShow" onChange={() => { setText(() => inputText.current.value) }} />
        </div>
      )
    }

    //画布组件
    function Paint(props) {
      //画笔属性
      const { color, size } = props.paintStyle;
      const { paints, activePaint, setPaints, method, isPadding, text } = props;
      const { useState, useEffect, useRef } = React;
      const [online, setOnline] = useState(false);
      let canvas = useRef(null)

      //初始化websocket
      function initWs() {
        let roomId = window.location.search.split('=')[1];
        ws = new WebSocket("ws://" + baseURL + "/websocket/" + 202211020755361);
        ws.onopen = function () {
          setOnline(() => true);
          console.log('连接成功')
        }
        ws.onclose = function () {
          setOnline(() => false);
          console.log('连接断开')
        }
        ws.onmessage = function (data) {
          drawImageOnPaint(data.data)
          console.log('收到信息')
        }
        ws.onerror = function (err) {
          // alert('连接出错了！！')
        }
      }

      function drawImageOnPaint(data) {
        let img = new Image();
        img.src = data;
        img.onload = () => {
          ctx.fillStyle = '#fff'
          ctx.fillRect(0, 0, canvas.current.width, canvas.current.height)
          ctx.drawImage(img, 0, 0, canvas.current.width, canvas.current.height)
        }
      }

      //初始化画布
      function initPaintSize() {
        canvas.current.width = canvas.current.clientWidth;
        canvas.current.height = canvas.current.clientHeight;
      }
      function initPaint() {
        initPaintSize();
        ctx = canvas.current.getContext('2d');
        if (paints[activePaint]) {
          drawImageOnPaint(paints[activePaint])
        } else {
          paints[activePaint] = canvas.current.toDataURL('image/png')
        }
        ctx.strokeStyle = color;
        initPaintEvent();
      }

      function initPaintEvent() {
        canvas.current.onmousedown = function (e) {
          if (method === Method.PEN) {
            ctx.beginPath();
            ctx.moveTo(e.offsetX, e.offsetY);
            canvas.current.onmousemove = function (e) {
              ctx.lineTo(e.offsetX, e.offsetY)
              ctx.stroke();
            }
          } else {
            const beginPosition = [e.offsetX, e.offsetY];
            const imageData = ctx.getImageData(0, 0, canvas.current.width, canvas.current.height);
            canvas.current.onmousemove = function (e) {
              ctx.beginPath();
              if (method === Method.TRIANGLE) {
                ctx.moveTo((beginPosition[0] + e.offsetX) / 2, beginPosition[1]);
                ctx.lineTo(e.offsetX, e.offsetY);
                ctx.lineTo(beginPosition[0], e.offsetY)
                ctx.closePath();
              } else if (method === Method.RECTANGLE) {
                ctx.rect(beginPosition[0], beginPosition[1], e.offsetX - beginPosition[0], e.offsetY - beginPosition[1]);
              } else if (method === Method.CIRCLE) {
                let centerX = (beginPosition[0] + e.offsetX) / 2;
                let centerY = (beginPosition[1] + e.offsetY) / 2;
                let radius = Math.sqrt(Math.pow(beginPosition[0] - e.offsetX, 2) + Math.pow(beginPosition[1] - e.offsetY, 2)) / 2;
                ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI)
              }
              ctx.putImageData(imageData, 0, 0, 0, 0, imageData.width, imageData.height);
              if (isPadding) {
                if (method === Method.TEXT) ctx.fillText(text, e.offsetX, e.offsetY);
                ctx.fill();
              } else {
                if (method === Method.TEXT) ctx.strokeText(text, e.offsetX, e.offsetY)
                ctx.stroke();
              }
            }
          }
          document.onmouseup = function () {
            if (canvas.current.onmousemove) {
              canvas.current.onmousemove = null;
              let base64 = canvas.current.toDataURL('image/png');
              setPaints(paints => { paints[activePaint] = base64; return paints })
              if (online) {
                ws.send(base64)
              }
            }
          }
        }
      }
      useEffect(() => {
        initWs();
        window.addEventListener('resize', () => { initPaintSize(), initWs() });
      }, [])

      useEffect(() => {
        initPaint();
      }, [online, activePaint])

      useEffect(() => {
        ctx.strokeStyle = color;
        ctx.fillStyle = color;
        ctx.lineWidth = size;
        ctx.font = size * 15 + "px Georgia";
        initPaintEvent();
      }, [color, size, method, isPadding, text])

      return (
        <canvas id="paint" ref={canvas}></canvas>
      )
    }

    function OtherPaints(props) {
      let { paints, activePaint, setActivePaint } = props;
      function changeActive(e) {
        let num = e.target.getAttribute('name');
        setActivePaint(() => num)
      }
      return (
        <div id="otherPaints">
          {
            paints.map((item, index) => {
              if (index != activePaint) {
                return (
                  <img className="otherPaint" key={index} onClick={changeActive} name={index} src={paints[index]} />
                )
              }
            })
          }
        </div>
      )
    }

    //总组件
    function App() {
      let { useState } = React;
      let [paints, setPaints] = useState([null]);
      let [activePaint, setActivePaint] = useState(0)
      let [color, setColor] = useState('red');
      let [size, setSize] = useState(1);
      let [method, setMethod] = useState(Method.PEN);
      let [isPadding, setIsPadding] = useState(false);
      let [text, setText] = useState('')

      let paintStyle = {
        color,
        size
      }

      let setPaintStyle = {
        setColor,
        setSize
      }
      return (
        <div id="App">
          <Tools setPaints={setPaints} paints={paints} setActivePaint={setActivePaint} />
          <Pen setPaintStyle={setPaintStyle} setMethod={setMethod} method={method} setIsPadding={setIsPadding} setText={setText} />
          <Paint paintStyle={paintStyle} paints={paints} activePaint={activePaint} setPaints={setPaints} method={method} isPadding={isPadding} text={text} />
          <OtherPaints paints={paints} activePaint={activePaint} setActivePaint={setActivePaint} />
        </div>
      )
    }
    let root = ReactDOM.createRoot(document.getElementById('root'))
    root.render(
      <App />
    )
  </script>
</body>

</html>